package com.bac.rentmap.web.controller.ad.add;

import java.util.*;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Required;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ValidationUtils;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;

import com.bac.rentmap.ad.add.AddFlatService;
import com.bac.rentmap.ad.crawler.phone.PhoneNormalizer;
import com.bac.rentmap.ad.flat.Constants;
import com.bac.rentmap.ad.flat.LocalAddress;
import com.bac.rentmap.ad.flat.crawler.FlatCrawledAd;
import com.bac.rentmap.ad.flat.crawler.localaddress.LocalAddressParser;
import com.bac.rentmap.ad.flat.image.FlatImageType;
import com.bac.rentmap.ad.flat.security.SecureIdGenerator;
import com.bac.rentmap.web.util.CityParser;
import com.google.appengine.api.blobstore.BlobstoreService;

/**
 * Used for control requests from addFlat page
 *
 * @author Sergey Zhmura
 */
@Controller
public class AddFlatController extends SimpleFormController {
    private static final Logger log = Logger.getLogger(AddFlatController.class
            .getName());

    public static final String JUST_ADDED = "flatAdJustAdded";
    private AddFlatService addFlatService;
    private LocalAddressParser localAddressParser;
    private PhoneNormalizer phoneNormalizer;
    private SecureIdGenerator secureIdGenerator;

    protected ModelAndView onSubmit(HttpServletRequest request,
            HttpServletResponse response, Object command, BindException errors)
            throws Exception {
        FlatAdBean flatAd = (FlatAdBean) command;
        FlatCrawledAd flatCrawledAd = transform(flatAd);
        String sessionId = request.getParameter("secureId");
        addFlatService.saveFlat(flatCrawledAd, getRelativeUrl(request),
                sessionId);
        // request.getSession().setAttribute(JUST_ADDED, Boolean.TRUE);
        response.sendRedirect("/ad/manage/view.do?secureId="
                + flatCrawledAd.getSecureId());
        return null;
    }

    private String getRelativeUrl(HttpServletRequest request) {

        String baseUrl = null;

        if ((request.getServerPort() == 80) || (request.getServerPort() == 443))
            baseUrl = request.getScheme() + "://" + request.getServerName()
                    + request.getContextPath();
        else
            baseUrl = request.getScheme() + "://" + request.getServerName()
                    + ":" + request.getServerPort() + request.getContextPath();

        return baseUrl;
    }

    private FlatCrawledAd transform(FlatAdBean flatAd) {
        FlatCrawledAd flatCrawledAd = new FlatCrawledAd();
        flatCrawledAd.setCity(flatAd.getCity());
        LocalAddress localAddress = new LocalAddress(flatAd
                .getLocalAddressPrefix(), flatAd.getParsedStreet(), flatAd
                .getBuilding(), flatAd.getBuildingPart());
        flatCrawledAd.setLocalAddress(localAddress);
        flatCrawledAd.setPrice(flatAd.getPrice());
        flatCrawledAd.setPricePerDay(flatAd.getPricePerDay() != null && flatAd.getPricePerDay());
        String phone = flatAd.getNormalizedPhone();
        flatCrawledAd.setPhone(phone);
        flatCrawledAd.setReadyForTransformation(true);
        if (flatAd.getDescription() != null)
            flatCrawledAd.setDescription(flatAd.getDescription());
        flatCrawledAd.setSourceUrl(Constants.INTERNAL_FLAT_AD_SOURCE_URL);
        if (flatAd.getRoomCount() != null)
            flatCrawledAd.setRoom(flatAd.getRoomCount().toString());
        flatCrawledAd.setSecureId(flatAd.getSecureId());
        if(flatAd.getEmail() != null && !flatAd.getEmail().isEmpty()){
        	flatCrawledAd.setEmail(flatAd.getEmail());
        }
        flatCrawledAd.setPublishingDate(new Date());
        return flatCrawledAd;
    }

    @Override
    protected void onBindAndValidate(HttpServletRequest request,
            Object command, BindException errors) throws Exception {
        super.onBindAndValidate(request, command, errors);
        rejectEmpty(errors, "city");
        rejectEmpty(errors, "street");
        rejectEmpty(errors, "building");
        rejectEmpty(errors, "roomCount");
        rejectEmpty(errors, "phone");
        rejectEmpty(errors, "price");
        FlatAdBean flatAd = (FlatAdBean) command;
        if (!errors.hasFieldErrors("phone")) {
            String phone = request.getParameter("phone");
            try {
                String normalizedPhone = phoneNormalizer.normalizePhone(phone);
                flatAd.setNormalizedPhone(normalizedPhone);
            } catch (IllegalArgumentException e) {
                log.warning("Can't normalize phone entered from UI: "
                        + flatAd.getPhone());
                errors.addError(new FieldError(getCommandName(), "phone",
                        phone, false,
                        new String[] { "error.field.format.phone" },
                        new Object[] { phone }, null));
            }
        }
    }

    private void rejectEmpty(BindException errors, String property) {
        ValidationUtils.rejectIfEmptyOrWhitespace(errors, property,
                "error.field.required");
    }

    @Override
    protected void onBind(HttpServletRequest request, Object command,
            BindException errors) throws Exception {
        FlatAdBean flatAd = (FlatAdBean) command;
        LocalAddress localAddress = null;
        String street = null;
        if (!errors.hasFieldErrors("street")) {
            street = request.getParameter("street");
            try {
                localAddress = localAddressParser.parse(street);
                flatAd.setParsedStreet(localAddress.getStreet());
                flatAd.setLocalAddressPrefix(localAddress.getPrefix());
            } catch (IllegalArgumentException e) {
                log.warning("Can't parse street " + street);
            }
        }
        super.onBind(request, command, errors);
    }

    @Required
    public void setLocalAddressParser(LocalAddressParser localAddressParser) {
        this.localAddressParser = localAddressParser;
    }

    @Override
    protected void initBinder(HttpServletRequest request,
            ServletRequestDataBinder binder) throws Exception {
        super.initBinder(request, binder);
        binder
                .registerCustomEditor(String.class, new StringTrimmerEditor(
                        true));
        binder.registerCustomEditor(Integer.class, new CustomNumberEditor(
                Integer.class, true));
    }

    @Override
    protected Map<String, Object> referenceData(HttpServletRequest request)
            throws Exception {
        Map<String, Object> res = new HashMap<String, Object>();
        res.put("imageTypes", getFlatImageTypeNames());
        String secureId = request.getParameter("secureId");
        res.put("secureId", secureId != null ? secureId : secureIdGenerator.generate());
        return res;
    }
    
    @Override
    protected Object formBackingObject(HttpServletRequest request)
            throws Exception {
        FlatAdBean res = (FlatAdBean) super.formBackingObject(request);
        String city = CityParser.parseCityFromDomain(request);
        if(city != null){
            res.setCity(city);
        }
        return res;
    }

    public static List<String> getFlatImageTypeNames() {
        List<String> res = new ArrayList<String>();
        for (FlatImageType flatImageType : FlatImageType.values()) {
            res.add(flatImageType.name());
        }
        return res;
    }

    @Required
    public void setAddFlatService(AddFlatService addFlatService) {
        this.addFlatService = addFlatService;
    }

    @Required
    public void setPhoneNormalizer(PhoneNormalizer phoneNormalizer) {
        this.phoneNormalizer = phoneNormalizer;
    }

    @Required
    public void setSecureIdGenerator(SecureIdGenerator secureIdGenerator) {
        this.secureIdGenerator = secureIdGenerator;
    }
}
